package com.huawei.codearts.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huawei.codearts.mapper.UserMapper;
import com.huawei.codearts.model.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;

@Slf4j
@Service
//@EnableAspectJAutoProxy
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired  // 自动装载的字段
    private UserMapper userMapper;

    @Override
    public List<User> getAllUsers() {
        return userMapper.getAllUsers();
    }

    @Override
    public User getUserById(Long id) {
        return userMapper.getUserById(id);
    }

    // XML方式 mapper 新增数据
    @Override
    public Long saveUser(User user) {
        return userMapper.insertUser(user);
    }

    @Override
    public Long updateUser(User user) {
        return userMapper.updateUser(user);
    }

    @Override
    public Long deleteUser(Long id) {
        return userMapper.deleteUser(id);
    }

    // 注解方式 mapper 新增数据
    @Override
    public Long insertUserAnnotation(User user) {
        return userMapper.insertUserAnnotation(user);
    }

    /**
     * 手动事务demo
     *
     * @param id
     * @return
     * @throws IOException
     */
    public Long updateWithTx(Long id) throws IOException {
        long success = 0L;
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(false);
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        try {
            // 模拟转账
            User user = userMapper.getUserById(6L);
            System.out.println("结果："+user);

            BigDecimal score = BigDecimal.valueOf(100);
            Long res1 = userMapper.updateWithTx(score, 1L);

            // 模拟网络异常
            System.out.println(10 / 0);

            Long res2 = userMapper.updateWithTx2(score, 2L);

            // 提交事务
            sqlSession.commit();
            success = 1L;
        } catch (Throwable e) {
            // 事务回滚
            sqlSession.rollback();
        }

        return success;
    }

    /**
     * spring事务管理器 开启事务
     * 参考文档：https://blog.51cto.com/u_16213464/7232622
     * 用 @Transactional 开启事务
     *
     * 步骤：
     * 1、配置数据源。例如：application.properties 或 application.yml 下的数据库配置
     * 2、配置事务管理器。在Spring Boot中，可以直接使用DataSourceTransactionManager作为事务管理器。例如：TransactionConfig 配置类
     * 3、配置事务通知。我们需要配置事务通知，即使用@Transactional注解来标记需要开启事务的方法。例如：UserServiceImpl类 在方法上添加：@Transactional注解
     * 4、配置切入点。指定哪些方法需要被事务通知拦截。例如：AopConfig 配置类
     * 5、注入事务通知。我们需要将事务通知注入到Spring容器中，以便在调用被事务标记的方法时，自动开启事务。例如：TransactionAspect 切面类
     * 总结:
     * 通过以上步骤，我们就成功地在Spring Boot项目中开启了MyBatis的事务支持。通过使用@Transactional注解标记需要开启事务的方法，
     * 并配置相应的事务管理器和事务通知，Spring Boot会自动处理事务的开启、提交和回滚。这样保证了数据库操作的一致性和完整性，提高了系统的稳定性。
     */
    @Transactional
    public Long springWithTx(Long id) {

        // 模拟转账
        User user = userMapper.getUserById(6L);
        System.out.println("结果："+user);

        BigDecimal score = BigDecimal.valueOf(100);
        Long res1 = userMapper.updateWithTx(score, 1L);

        // 模拟网络异常
        System.out.println(10 / 0);

        Long res2 = userMapper.updateWithTx2(score, 2L);

        return 1L;
    }

}


